package com.core.managers;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest;

import com.core.protocols.IKVObject;
import com.core.utils.GlobalConstants;
import com.core.utils.GlobalConstants.HibernateSQLAction;
import com.core.utils.URLStringBuilder;
import com.model.project.ProjectItem;
import com.model.project.ProjectTask;
import com.model.project.TeamMember;
import com.model.project.Version;
import com.model.report.Report;
import com.model.user.User;
import com.model.user.UserGroup;
import com.model.user.UserRole;

public class ServletManager {

	private Map <Class <? extends IKVObject>, HashMap <HibernateSQLAction, String>> avatarsMap;
	private Map <Class <? extends IKVObject>, HashMap <HibernateSQLAction, String>> redirectionMap;
	private Map <String, HashMap <String, String>>                                  servletParamsMap;

	private static ServletManager                                                   Instance = null;



	public static ServletManager sharedInstance () {

		if ( Instance == null )
			Instance = new ServletManager();
		return Instance;
	}



	private ServletManager() {

		avatarsMap = new HashMap <Class <? extends IKVObject>, HashMap <HibernateSQLAction, String>>();
		this.buildAvatarsMap();

		redirectionMap = new HashMap <Class <? extends IKVObject>, HashMap <HibernateSQLAction, String>>();
		this.buildRedirectionMap();

		servletParamsMap = new HashMap <String, HashMap <String, String>>();
		this.buildServletParamsMap();

	}



	public void saveServletState ( String servletName,
	                               String query ) {

	}



	public String servletSavedState ( String servletName ) {

		return null;
	}



	/**
	 * Check, whether request posses default servlet parameter
	 * 
	 * @param request
	 * @return
	 */
	public boolean hasMethodGETRedirectionParamInRequest ( HttpServletRequest request ) {

		String servletName = request.getRequestURI().replaceFirst(request.getContextPath(), "");
		if ( servletName == null ) {
			return false;
		}
		Map <String, String> servletRedirectionParams = this.servletParamsMap.get(servletName);
		if ( servletRedirectionParams == null ) {
			return false;
		}

		boolean result = false;
		Map <String, String[]> map = request.getParameterMap();
		for ( String key : servletRedirectionParams.keySet() ) {
			if ( map.get(key) != null ) {
				result = true;
				break;
			}
		}
		return result;
	}



	private String requestMapParamToString ( Map <String, String[]> requestMap,
	                                         String key ) {

		boolean shouldUseCommaSeparator = false;
		StringBuilder sbRequestParam = new StringBuilder();
		String[] requestParams = requestMap.get(key);
		for ( String requestParam : requestParams ) {
			if ( shouldUseCommaSeparator ) {
				sbRequestParam.append(String.format(";%s", requestParam));
			} else {
				sbRequestParam.append(requestParam);
				shouldUseCommaSeparator = true;
			}
		}

		return sbRequestParam.toString();

	}



	/**
	 * returns requery with default servlet parameter
	 * 
	 * @param request
	 * @param servletConfig
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public String methodGETRedirectionWithDefaultParamForRequest ( HttpServletRequest request,
	                                                               ServletConfig servletConfig ) {

		String redirection = null;

		String servletName = request.getRequestURI().replaceFirst(request.getContextPath(), "");
		if ( servletName == null ) {
			return null;
		}


		HashMap <String, String> servletParams = this.servletParamsMap.get(servletName);
		if ( servletParams == null ) {
			redirection = servletConfig.getInitParameter("getRedirect");
			return redirection;
		}


		Map <String, String> defParams = (HashMap <String, String>) servletParams.clone();

		StringBuilder sb = new StringBuilder();
		sb.append(servletName);

		Map <String, String[]> requestMap = request.getParameterMap();
		URLStringBuilder urlStringBuilder = new URLStringBuilder();

		for ( String key : requestMap.keySet() ) {

			String requestParamValue = this.requestMapParamToString(requestMap, key);

			boolean canUseDefault = (defParams.get(key) != null);
			String defaultParamValue = null;
			if ( canUseDefault ) {
				defaultParamValue = defParams.get(key).toString();
			}

			String requestParam = String.format("%s=%s", key, canUseDefault ? defaultParamValue : requestParamValue);
			urlStringBuilder.add(requestParam);

			if ( canUseDefault ) {
				defParams.remove(key);
			}
		}



		for ( String key : defParams.keySet() ) {
			String defaultParamValue = defParams.get(key).toString();
			String defParam = String.format("%s=%s", key, defaultParamValue);
			urlStringBuilder.add(defParam);
		}

		String sParams = urlStringBuilder.toString();
		if ( sParams.trim().length() > 0 ) {
			sb.append(String.format("?%s", sParams));
		}
		redirection = sb.toString();



		return redirection;
	}



	/**
	 * returns servlet for class action
	 * 
	 * @param clazz
	 * @param action
	 * @return
	 */
	public String servletNameForClassAction ( Class <? extends IKVObject> clazz,
	                                          HibernateSQLAction action ) {

		String result = null;
		if ( redirectionMap == null ) {
			return null;
		}

		Map <HibernateSQLAction, String> map = this.redirectionMap.get(clazz);
		if ( map == null ) {
			return null;
		}

		result = map.get(action);


		return result;
	}



	/**
	 * creates default servlet params mapping
	 */
	private void buildServletParamsMap () {

		HashMap <String, String> servletParam = null;

		servletParam = new HashMap <String, String>();
		servletParam.put("selectedTab", "1");
		servletParamsMap.put("/" + GlobalConstants.SERVLET_PROJECTLIST, servletParam);

		servletParam = new HashMap <String, String>();
		servletParam.put("selectedTab", "1");
		servletParamsMap.put("/" + GlobalConstants.SERVLET_PROJECTINFO, servletParam);

		servletParam = new HashMap <String, String>();
		servletParam.put("selectedTab", "1");
		servletParamsMap.put("/" + GlobalConstants.SERVLET_TASKINFO, servletParam);

		servletParam = new HashMap <String, String>();
		servletParam.put("selectedTab", "1");
		servletParamsMap.put("/" + GlobalConstants.SERVLET_ADMINISTRATION, servletParam);

		servletParam = new HashMap <String, String>();
		servletParam.put("selectedTab", "1");
		servletParamsMap.put("/" + GlobalConstants.SERVLET_USERINFO, servletParam);

		servletParam = new HashMap <String, String>();
		servletParam.put("selectedTab", "1");
		servletParamsMap.put("/" + GlobalConstants.SERVLET_VERSIONINFO, servletParam);

		servletParam = new HashMap <String, String>();
		servletParam.put("selectedTab", "1");
		servletParamsMap.put("/" + GlobalConstants.SERVLET_ROLEINFO, servletParam);

		servletParam = new HashMap <String, String>();
		servletParam.put("selectedTab", "1");
		servletParamsMap.put("/" + GlobalConstants.SERVLET_REPORTINFO, servletParam);

		servletParam = new HashMap <String, String>();
		servletParam.put("selectedTab", "1");
		servletParamsMap.put("/" + GlobalConstants.SERVLET_TEAMMEMBERINFO, servletParam);
	}



	/**
	 * creates default servlet post redirection mapping
	 */
	private void buildRedirectionMap () {

		HashMap <HibernateSQLAction, String> classMap = null;

		/**
		 * 
		 * Project
		 * 
		 */
		classMap = new HashMap <HibernateSQLAction, String>();
		classMap.put(HibernateSQLAction.CREATE, GlobalConstants.SERVLET_PROJECTADD);
		classMap.put(HibernateSQLAction.DELETE, GlobalConstants.SERVLET_PROJECTDELETE);
		classMap.put(HibernateSQLAction.UPDATE, GlobalConstants.SERVLET_PROJECTUPDATE);
		classMap.put(HibernateSQLAction.SELECT, GlobalConstants.SERVLET_PROJECTINFO);
		redirectionMap.put(ProjectItem.class, classMap);


		/**
		 * 
		 * Project Task
		 * 
		 */
		classMap = new HashMap <HibernateSQLAction, String>();
		classMap.put(HibernateSQLAction.CREATE, GlobalConstants.SERVLET_TASKADD);
		classMap.put(HibernateSQLAction.DELETE, GlobalConstants.SERVLET_TASKDELETE);
		classMap.put(HibernateSQLAction.UPDATE, GlobalConstants.SERVLET_TASKUPDATE);
		classMap.put(HibernateSQLAction.SELECT, GlobalConstants.SERVLET_TASKINFO);
		redirectionMap.put(ProjectTask.class, classMap);

		/**
		 * 
		 * Project Version
		 * 
		 */
		classMap = new HashMap <HibernateSQLAction, String>();
		classMap.put(HibernateSQLAction.CREATE, GlobalConstants.SERVLET_VERSIONINFO);
		classMap.put(HibernateSQLAction.DELETE, GlobalConstants.SERVLET_TASKSLIST);
		classMap.put(HibernateSQLAction.UPDATE, GlobalConstants.SERVLET_VERSIONINFO);
		classMap.put(HibernateSQLAction.SELECT, GlobalConstants.SERVLET_TASKINFO);
		redirectionMap.put(Version.class, classMap);

		/**
		 * 
		 * Report
		 * 
		 */
		classMap = new HashMap <HibernateSQLAction, String>();
		classMap.put(HibernateSQLAction.CREATE, GlobalConstants.SERVLET_REPORTADD);
		classMap.put(HibernateSQLAction.DELETE, GlobalConstants.SERVLET_REPORTDELETE);
		classMap.put(HibernateSQLAction.UPDATE, GlobalConstants.SERVLET_REPORTUPDATE);
		classMap.put(HibernateSQLAction.SELECT, GlobalConstants.SERVLET_REPORTINFO);
		redirectionMap.put(Report.class, classMap);

		/**
		 * 
		 * TEAM
		 * 
		 */
		classMap = new HashMap <HibernateSQLAction, String>();
		classMap.put(HibernateSQLAction.CREATE, GlobalConstants.SERVLET_TEAMMEMBERADD);
		classMap.put(HibernateSQLAction.DELETE, GlobalConstants.SERVLET_TEAMMEMBERDELETE);
		classMap.put(HibernateSQLAction.UPDATE, GlobalConstants.SERVLET_TEAMMEMBERUPDATE);
		classMap.put(HibernateSQLAction.SELECT, GlobalConstants.SERVLET_TEAMMEMBERINFO);
		redirectionMap.put(TeamMember.class, classMap);
	}



	/**
     *
     */
	private void buildAvatarsMap () {

		HashMap <HibernateSQLAction, String> classMap = null;

		/**
		 * 
		 * Project
		 * 
		 */
		classMap = new HashMap <HibernateSQLAction, String>();
		classMap.put(HibernateSQLAction.SELECT, "img/entities/ProjectItem.png");
		avatarsMap.put(ProjectItem.class, classMap);

		/**
		 * 
		 * Task
		 * 
		 */
		classMap = new HashMap <HibernateSQLAction, String>();
		classMap.put(HibernateSQLAction.SELECT, "img/entities/Task.png");
		avatarsMap.put(ProjectTask.class, classMap);
		/**
		 * 
		 * User
		 * 
		 */
		classMap = new HashMap <HibernateSQLAction, String>();
		classMap.put(HibernateSQLAction.SELECT, "img/entities/User.png");
		avatarsMap.put(User.class, classMap);
		/**
		 * 
		 * Group
		 * 
		 */
		classMap = new HashMap <HibernateSQLAction, String>();
		classMap.put(HibernateSQLAction.SELECT, "img/entities/UserGroup.png");
		avatarsMap.put(UserGroup.class, classMap);
		/**
		 * 
		 * Version
		 * 
		 */
		classMap = new HashMap <HibernateSQLAction, String>();
		classMap.put(HibernateSQLAction.SELECT, "img/entities/Version.png");
		avatarsMap.put(Version.class, classMap);
		/**
		 * 
		 * Role
		 * 
		 */
		classMap = new HashMap <HibernateSQLAction, String>();
		classMap.put(HibernateSQLAction.SELECT, "img/entities/UserRole.png");
		avatarsMap.put(UserRole.class, classMap);
		/**
		 * 
		 * team member
		 * 
		 */
		classMap = new HashMap <HibernateSQLAction, String>();
		classMap.put(HibernateSQLAction.SELECT, "img/entities/TeamMember.png");
		avatarsMap.put(TeamMember.class, classMap);
	}



	/**
	 * 
	 * @param clazz
	 * @param action
	 * @return
	 */

	public String avatarNameForEntity ( Class <? extends IKVObject> clazz,
	                                    HibernateSQLAction action ) {

		if ( clazz == null ) {
			return null;
		}


		HashMap <HibernateSQLAction, String> classMap = avatarsMap.get(clazz);
		if ( classMap == null ) {
			return null;
		}


		return classMap.get(action);
	}


}
